package com.hdu.mockService.handler;

import com.hdu.mockService.annotation.RandomString;
import com.hdu.mockService.enums.CharType;
import lombok.val;
import org.apache.commons.collections4.CollectionUtils;



import static com.hdu.mockService.utils.PredictionUtils.unValidParam;
import static com.hdu.mockService.utils.RandomStringGenerator.generateRandomString;
import static com.hdu.mockService.utils.ReflectionUtils.getFieldsByTargetAnnotation;

public class StringMockHandler implements IMockHandler {

    private final static int MAX_GENERATE_LEN = 50;

    @Override
    public void partitionMock(Object mockObj) {
        val mockStringFields = getFieldsByTargetAnnotation(mockObj.getClass(), RandomString.class);
        if (CollectionUtils.isEmpty(mockStringFields)) {
            return;
        }
        mockStringFields.forEach(field -> {
            try {
                field.setAccessible(true);
                int fixLen = field.getAnnotation(RandomString.class).fixedLength();
                int minLen = field.getAnnotation(RandomString.class).minLength();
                int maxLen = field.getAnnotation(RandomString.class).maxLength();
                CharType[] charTypes = field.getAnnotation(RandomString.class).charTypes();
                field.set(mockObj, getRandomString(fixLen, minLen, maxLen, charTypes));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        });
    }

    protected String getRandomString(
            int fixLen,
            int minLen,
            int maxLen,
            CharType[] charTypes) throws IllegalArgumentException {

        validInput(fixLen, minLen, maxLen, charTypes);

        boolean containsUpperCase = false;
        boolean containsLowerCase = false;
        boolean containsNumber = false;

        for (CharType charType : charTypes) {
            switch (charType) {
                case UPPER_CASE:
                    containsUpperCase = true;
                    break;
                case LOWER_CASE:
                    containsLowerCase = true;
                    break;
                case NUMBER:
                    containsNumber = true;
                    break;
            }
        }

        int finalMinLen = 0;
        int finalMaxLen = 0;
        if (fixLen == -1) {
            finalMinLen = (minLen == -1) ? 1 : minLen;
            finalMaxLen = (maxLen == -1) ? MAX_GENERATE_LEN : maxLen;

        }

        return generateRandomString(
                fixLen == -1 ? finalMinLen : fixLen,
                fixLen == -1 ? finalMaxLen : fixLen,
                containsUpperCase,
                containsLowerCase,
                containsNumber
        );
    }

    private void validInput(int fixedLength, int minLength, int maxLength, CharType[] charTypes) {

        unValidParam(
                fixedLength != -1 && (minLength != -1 || maxLength != -1),
                "fixedLength and minLength/maxLen can not be set at the same time"
        );

        unValidParam(
                fixedLength == -1 && minLength == -1 && maxLength == -1,
                "fixedLength/minLength/maxLen must be set"
        );

        unValidParam(
                charTypes == null || charTypes.length == 0,
                "charTypes must be set"
        );

        unValidParam(
                maxLength > MAX_GENERATE_LEN,
                "maxLength must less eq than " + MAX_GENERATE_LEN
        );
    }

}
